package cn.edu.nsmc.modules.sys.service.impl;

import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

import cn.edu.nsmc.common.utils.R;
import cn.edu.nsmc.common.utils.SheetAuditStatusEnum;
import cn.edu.nsmc.config.Constant;
import cn.edu.nsmc.modules.sys.dao.SysUserDao;
import cn.edu.nsmc.modules.sys.entity.SysUserEntity;
import cn.edu.nsmc.modules.sys.entity.SysWorksheetAuditNode;
import cn.edu.nsmc.modules.sys.entity.vo.SysWorksheetRecordVo;
import cn.edu.nsmc.modules.sys.form.req.ReqFeeBackWorksheetBody;
import cn.edu.nsmc.modules.sys.form.req.ReqWorkSheetListBody;
import cn.edu.nsmc.modules.sys.form.req.WorksheetRecordExcel;
import cn.edu.nsmc.modules.sys.service.SysWorksheetAuditNodeService;
import cn.edu.nsmc.modules.sys.service.SysWorksheetRepairService;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.util.MapUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import cn.edu.nsmc.common.utils.PageUtils;
import cn.edu.nsmc.common.utils.Query;
import cn.edu.nsmc.modules.sys.dao.SysWorksheetRecordDao;
import cn.edu.nsmc.modules.sys.entity.SysWorksheetRecord;
import cn.edu.nsmc.modules.sys.form.req.ReqAssignWorksheetBody;
import cn.edu.nsmc.modules.sys.service.SysWorksheetRecordService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import javax.servlet.http.HttpServletResponse;

/**
 * Created by Lee Yian on 2024/2/24 19:29
 */
@Service("sysWorksheetRecordService")
public class SysWorksheetRecordServiceImpl extends ServiceImpl<SysWorksheetRecordDao, SysWorksheetRecord> implements SysWorksheetRecordService {
    private final SysUserDao sysUserDao;

    @Autowired
    private SysWorksheetRepairService sysWorksheetRepairService;
    private final SysWorksheetAuditNodeService sysWorksheetAuditNodeService;
    @Autowired
    public SysWorksheetRecordServiceImpl(SysUserDao sysUserDao, SysWorksheetAuditNodeService sysWorksheetAuditNodeService) {
        this.sysUserDao = sysUserDao;
        this.sysWorksheetAuditNodeService = sysWorksheetAuditNodeService;
    }

    @Autowired
    private SysWorksheetRecordDao sysWorksheetRecordDao;
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        QueryWrapper<SysWorksheetRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("apply_time");

        IPage<SysWorksheetRecord> page = this.page(
                new Query<SysWorksheetRecord>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    /**
     * 条件查询工单列表
     * @param params  分页参数
     * @param workSheetListBody 查询条件
     * @return 工单列表
     */
    @Override
    public PageUtils queryPage(Map<String, Object> params, ReqWorkSheetListBody workSheetListBody) {
        LambdaQueryWrapper<SysWorksheetRecord> queryWrapper = new LambdaQueryWrapper<>();

        // 1. 拼接参数
        queryWrapper
                // 第一个是参数决定这个 where 条件会不会拼进 查询 sql，第二个参数是列名，第三个参数是值
                .eq( StringUtils.isNotBlank(workSheetListBody.getAuditStatus() ),
                        SysWorksheetRecord::getAuditStatus, workSheetListBody.getAuditStatus() )
                // 给条件构造器拼接 and 条件, and 的第一个参数决定这个条件会不会拼进查询 sql，
                // 第二个参数固定写法，输入一个条件构造器
                .and(StringUtils.isNotBlank(workSheetListBody.getRepairmanId() ),
                        wrapper -> wrapper.eq(SysWorksheetRecord::getRepairmanId, workSheetListBody.getRepairmanId() ) )
                .and(StringUtils.isNotBlank(workSheetListBody.getAuditorId() ),
                        wrapper -> wrapper.eq(SysWorksheetRecord::getAuditorId, workSheetListBody.getAuditorId() ) );


        // 2 & 3.  Combined date range and sorting logic
        if (workSheetListBody.getRecentDays() != null) {
            // 2.1 处理日期范围
            if (workSheetListBody.getRecentDays() > 0) {
                LocalDate endDate = LocalDate.now();
                LocalDate startDate = endDate.minusDays(workSheetListBody.getRecentDays());
                queryWrapper.between(SysWorksheetRecord::getApplyTime, startDate, endDate); // Use LocalDate directly
                queryWrapper.orderByDesc(SysWorksheetRecord::getApplyTime);
            }
            // 2.2 处理排序逻辑
            else if (workSheetListBody.getRecentDays() == -1) {
                queryWrapper.orderByAsc(SysWorksheetRecord::getApplyTime);
            }
            // 2.3 处理其他情况
            else { //  Handles recentDays == 0 and other negative values (treat as default descending)
                queryWrapper.orderByDesc(SysWorksheetRecord::getApplyTime);
            }
        } else { // Default sorting when recentDays is null
            queryWrapper.orderByDesc(SysWorksheetRecord::getApplyTime);
        }
        // 4. 执行查询
        IPage<SysWorksheetRecord> page = this.page(
                new Query<SysWorksheetRecord>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    @Override
    public Map<Integer, List<SysWorksheetRecord>> wxList(Long userId) {
        List<SysWorksheetRecord> list = sysWorksheetRecordDao.wxList(userId);

        Map<Integer, List<SysWorksheetRecord>> map = new HashMap<>();
        List<SysWorksheetRecord> all = new ArrayList<>();
        List<SysWorksheetRecord> process = new ArrayList<>();
        List<SysWorksheetRecord> success = new ArrayList<>();
        List<SysWorksheetRecord> fail = new ArrayList<>();

        for (SysWorksheetRecord item : list){
            if(item.getAuditStatus() == 1 || item.getAuditStatus() == 2){
                success.add(item);
            }else if(item.getAuditStatus() == 0 || item.getAuditStatus() == 3){
                process.add(item);
            }else if(item.getAuditStatus() == -1){
                fail.add(item);
            }

            if(item.getAuditStatus() == 2){
                item.setRepairEntity(sysWorksheetRepairService.getById(item.getId()));
            }

            all.add(item);
        }
        map.put(1,all);
        map.put(2,process);
        map.put(3,success);
        map.put(4,fail);

        return map;
    }

    /**
     * 审批工单并指派维修人员
     * @param reqAssignWorksheetBody 审批人id、工单id、维修人员id
     * @return 指派结果
     */
    @Override
    @Transactional
    public String assignWorksheet(ReqAssignWorksheetBody reqAssignWorksheetBody) {
        // 对参数进行校验
        SysWorksheetRecord worksheetRecordById = baseMapper.selectById(reqAssignWorksheetBody.getWorksheetId());
        if(null == worksheetRecordById){
            throw new IllegalArgumentException("业务不存在");
        }
        SysUserEntity sysUserEntity = sysUserDao.selectById(reqAssignWorksheetBody.getAssignerId());
        if(null == sysUserEntity){
            throw new IllegalArgumentException("审批人不存在");
        }
        SysUserEntity sysRepairman = sysUserDao.selectById(reqAssignWorksheetBody.getRepairmanId());
        if(null == sysRepairman){
            throw new IllegalArgumentException("维修人员不存在");
        }

        //  判断工单是否已经指派维修人员
        if(worksheetRecordById.getAuditStatus()  != SheetAuditStatusEnum.PENDING.getValue()){
            throw new IllegalArgumentException("拒绝执行，业务已有维修人员 "+sysRepairman.getUsername());
        }

        // 1. 更新工单记录表信息
        worksheetRecordById.setRepairmanId(reqAssignWorksheetBody.getRepairmanId());
        worksheetRecordById.setAuditorId(reqAssignWorksheetBody.getAssignerId());
        worksheetRecordById.setAuditStatus(SheetAuditStatusEnum.WAIT_REPAIR.getValue());      // 工单状态 3，已分配维修人员
        // 1.1 执行更新
        boolean b = updateById(worksheetRecordById);
        if (!b){
            throw new RuntimeException("未知异常，指派失败");
        }
        // 2，更新工单节点表信息
        SysWorksheetAuditNode sysWorksheetAuditNode = new SysWorksheetAuditNode();
        sysWorksheetAuditNode.setWorksheetId(reqAssignWorksheetBody.getWorksheetId())
                .setAuditor(Long.valueOf(reqAssignWorksheetBody.getAssignerId()))
                .setAuditResult(sysUserEntity.getUsername()+" 指派给维修人员："+sysRepairman.getUsername());
        // 2.1 执行插入
        sysWorksheetAuditNodeService.save(sysWorksheetAuditNode);
        return sysUserEntity.getUsername()+"  指派给维修人员："+sysRepairman.getUsername();
    }

    /**
     * 反馈工单处理结果
     * 工单状态 0：未处理 1：已指派 2：已处理
     * @param feedBackBody 工单id、维修人员id、处理结果
     * @return 反馈结果
     */
    @Override
    @Transactional
    public String feedbackWorksheet(ReqFeeBackWorksheetBody feedBackBody) {
        SysWorksheetRecord worksheetRecordById = baseMapper.selectById(feedBackBody.getWorksheetId());
        if(null == worksheetRecordById){
            throw new IllegalArgumentException("工单不存在");
        }
        SysUserEntity sysUserEntity = sysUserDao.selectById(feedBackBody.getRepairmanId());
        if(null == sysUserEntity){
            throw new IllegalArgumentException("操作用户不存在");
        }
        //  判断工单是否已经被处理，DONE、REJECTED、APPROVED 三种状态都是完成状态
        if(worksheetRecordById.getAuditStatus()  == SheetAuditStatusEnum.DONE.getValue()
                || worksheetRecordById.getAuditStatus()  == SheetAuditStatusEnum.REJECTED.getValue()
                || worksheetRecordById.getAuditStatus() == SheetAuditStatusEnum.APPROVED.getValue() ) {
            throw new IllegalArgumentException("工单已被处理过 ");
        }

        // 1. 更新工单记录表信息
        worksheetRecordById.setAuditStatus(SheetAuditStatusEnum.DONE.getValue());      // 变更工单状态为已处理
        worksheetRecordById.setEndTime(new Date());     // 设置工单结束时间
        if(StringUtils.isNotBlank(feedBackBody.getReplyInfo() ) ){  // 设置工单回执
            worksheetRecordById.setReplyInfo(feedBackBody.getReplyInfo());
        }

        // 1.1 执行更新
        boolean b = updateById(worksheetRecordById);
        if (!b){
            throw new IllegalStateException("未知异常，反馈失败");
        }
        // 2，更新工单节点表信息
        SysWorksheetAuditNode sysWorksheetAuditNode = new SysWorksheetAuditNode();
        sysWorksheetAuditNode.setWorksheetId(feedBackBody.getWorksheetId())
                .setAuditor(feedBackBody.getRepairmanId())
                .setAuditResult(sysUserEntity.getUsername()+" 已完成工单");
        if (StringUtils.isNotBlank(feedBackBody.getComment())){
            sysWorksheetAuditNode.setComment(feedBackBody.getComment());
        }

        // 2.1 执行插入
        boolean save = sysWorksheetAuditNodeService.save(sysWorksheetAuditNode);
        if (!save){
            throw new IllegalStateException("未知异常，反馈失败");
        }

        return sysUserEntity.getUsername()+" 处理工单成功";
    }

    @Override
    public String rejectWorksheet(ReqFeeBackWorksheetBody feedBackBody) {
        SysWorksheetRecord worksheetRecordById = baseMapper.selectById(feedBackBody.getWorksheetId());
        if(null == worksheetRecordById){
            throw new IllegalArgumentException("工单不存在");
        }
        SysUserEntity sysUserEntity = sysUserDao.selectById(feedBackBody.getRepairmanId());
        if(null == sysUserEntity){
            throw new IllegalArgumentException("操作用户不存在");
        }
        //  判断工单是否已经被处理
        if(worksheetRecordById.getAuditStatus()  != SheetAuditStatusEnum.PENDING.getValue()){
            throw new IllegalArgumentException("工单已被处理过 ");
        }

        // 1. 更新工单记录表信息
        worksheetRecordById.setAuditStatus(SheetAuditStatusEnum.REJECTED.getValue());      // 变更工单状态为已拒绝
        worksheetRecordById.setEndTime(new Date());     // 设置工单结束时间
        if(StringUtils.isNotBlank(feedBackBody.getReplyInfo() ) ){  // 设置工单回执
            worksheetRecordById.setReplyInfo(feedBackBody.getReplyInfo());
        }

        // 1.1 执行更新
        boolean b = updateById(worksheetRecordById);
        if (!b){
            throw new IllegalStateException("未知异常，反馈失败");
        }
        // 2，更新工单节点表信息
        SysWorksheetAuditNode sysWorksheetAuditNode = new SysWorksheetAuditNode();
        sysWorksheetAuditNode.setWorksheetId(feedBackBody.getWorksheetId())
                .setAuditor(feedBackBody.getRepairmanId())
                .setAuditResult(sysUserEntity.getUsername()+" 已拒绝工单");
        if (StringUtils.isNotBlank(feedBackBody.getComment())){
            sysWorksheetAuditNode.setComment(feedBackBody.getComment());
        }

        // 2.1 执行插入
        boolean save = sysWorksheetAuditNodeService.save(sysWorksheetAuditNode);
        if (!save){
            throw new IllegalStateException("未知异常，反馈失败");
        }

        return sysUserEntity.getUsername()+" 处理工单成功";
    }

    @Override
    public R getList(SysWorksheetRecord sysWorksheetRecord,Integer page,Integer size) {
        List<SysWorksheetRecordVo> list = sysWorksheetRecordDao.getList(page, size, sysWorksheetRecord);
        Integer total = sysWorksheetRecordDao.getNumber(sysWorksheetRecord);
        Map<String,Object> data = new HashMap<>();
        data.put("list",list);
        data.put("total",total);
        return R.success("查询成功",data);
    }

    @Override
    public R commentWorksheet(Long id, String note) {
        sysWorksheetRecordDao.commentWorksheet(id, note);
        return R.ok("备注成功");
    }

    @Override
    public R auditWorksheet(List<Long> ids, Integer auditType, String cause) {
        if (auditType==-1){
            auditType=-1;
        }else {
            auditType=1;
        }
        sysWorksheetRecordDao.auditWorksheet(ids, auditType,cause);
        if (auditType==-1){// TODO: 2024/4/3 增加状态
            return R.ok("批量拒绝工单成功");
        }else {
            return R.ok("批量允许工单成功");
        }
    }

    @Override
    public void export(ReqWorkSheetListBody listBody, HttpServletResponse response) {
        //dataDao.getSummaryList(summaryForm);
        Integer len = sysWorksheetRecordDao.countExport(listBody);
        try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), WorksheetRecordExcel.class).autoCloseStream(Boolean.FALSE).build()) {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("维修工单列表", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            WriteSheet writeSheet = EasyExcel.writerSheet("下载数据").build();
            if (len==0) {
                List<WorksheetRecordExcel> list = new ArrayList<>();
                WorksheetRecordExcel worksheetRecordExcel = new WorksheetRecordExcel();
                worksheetRecordExcel.setApplicantName("当前搜索条件无数据，请更改条件后重试");
                worksheetRecordExcel.setMemo("当前无数据");
                list.add(worksheetRecordExcel);
                excelWriter.write(list, writeSheet);
            }else {
                int cnt = len / 10000;
                for (int j = 0; j < cnt; j++) {
                    // 分页去数据库查询数据 这里可以去数据库查询每一页的数据
                    List<WorksheetRecordExcel> list = sysWorksheetRecordDao.export(j * 10000, 10000,listBody);
                    for (WorksheetRecordExcel worksheetRecordExcel : list) {
                        worksheetRecordExcel.setAuditStatusName(Constant.INT_TO_AUDIT_STATUS.get(Long.valueOf(worksheetRecordExcel.getAuditStatus())));
                    }
                    excelWriter.write(list, writeSheet);
                }
                if (len % 10000 > 0) {
                    List<WorksheetRecordExcel> list = sysWorksheetRecordDao.export(cnt * 10000, len % 10000,listBody);
                    for (WorksheetRecordExcel worksheetRecordExcel : list) {
                        worksheetRecordExcel.setAuditStatusName(Constant.INT_TO_AUDIT_STATUS.get(Long.valueOf(worksheetRecordExcel.getAuditStatus())));
                    }
                    excelWriter.write(list, writeSheet);
                }
            }
        } catch (Exception e) {
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            Map<String, String> map = MapUtils.newHashMap();
            map.put("status", "failure");
            map.put("message", "下载文件失败" + e.getMessage());
            try {
                response.getWriter().println(JSON.toJSONString(map));
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }
    }

    public R addRecordByAdmin(@RequestBody SysWorksheetRecord sysWorksheetRecord){
        sysWorksheetRecord.setApplyTime(new Date());
        return sysWorksheetRecordDao.addRecordByAdmin(sysWorksheetRecord);
    }
    // TODO 调用公共的判断逻辑
    // private SysWorksheetRecord validateParameters(Long worksheetId, Long userId, Long repairmanId) {
    //     SysWorksheetRecord worksheetRecordById = baseMapper.selectById(worksheetId);
    //     if(null == worksheetRecordById){
    //         throw new IllegalArgumentException("工单不存在");
    //     }
    //     SysUserEntity sysUserEntity = sysUserDao.selectById(userId);
    //     if(null == sysUserEntity){
    //         throw new IllegalArgumentException("用户不存在");
    //     }
    //     if(repairmanId != null) {
    //         SysUserEntity sysRepairman = sysUserDao.selectById(repairmanId);
    //         if(null == sysRepairman){
    //             throw new IllegalArgumentException("维修人员不存在");
    //         }
    //     }
    //     return worksheetRecordById;
    // }

}
